 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace GAscheduler
{
    /// <summary>
    /// This class is a blueprint for all other classes that inherit from it, of which 
    ///     there are three. It has no defined functions (only an abstract which is 
    ///     overriden by the children classes) and it only contains variables that all 
    ///     children classes must have.
    /// </summary>
    abstract class RuleCode
    {
        public RuleToken rtCode; // all classes must have a rule code
        public ArrayList alList; // and a list of objects

        // they must also have a way to check a given schedule to make sure the rule they represent is followed
        public abstract bool CrosscheckRule(Schedule sch); 
    } // RuleCode

    /// <summary>
    /// Class for holding importand data about this rule type. Inherits from RuleCode.
    /// </summary>
    class RMCode : RuleCode
    {
        public string sClassroom; // a classroom in which the list of classes can be held
        public bool bMust;        // whether or not all classes in the list must be held in the above classroom

        /// <summary>
        /// Constructor. Assigns all important data to the data members of the class.
        /// </summary>
        /// <param name="rtInCode"></param>
        /// <param name="sInClassroom"></param>
        /// <param name="bInMust"></param>
        /// <param name="alInList"></param>
        public RMCode(RuleToken rtInCode, string sInClassroom, bool bInMust, ArrayList alInList)
        {
            rtCode = rtInCode;
            sClassroom = sInClassroom;
            bMust = bInMust;
            alList = alInList;
        } // RMCode

        /// <summary>
        /// Overrides the abstract function in the parent abstract class RuleCode. Checks the
        ///     schedule to see if the rule is followed by all genes.
        /// </summary>
        /// <param name="sch"></param>
        /// <returns></returns>
        public override bool CrosscheckRule(Schedule sch)
        {
            if (bMust) // if all classes MUST be in that room,
            {
                foreach (RuleToken t in alList) // then every class in the list...
                {
                    foreach (Gene g in sch)     // must appear in the schedule...
                    {
                        // as being held in the same room
                        if (g.getRoom() == sClassroom && g.getCourse() != t.GetTokenName())
                            return false; // and if not, shame on the schedule
                    }
                }
                return true; // if we never found an instance that proved false, the the rule has been met
            }
            else // if all classes only CAN be in that room,
            {
                foreach (Gene g in sch)                 // then every class...
                {
                    if (g.getRoom() == sClassroom)      // happening in that room...
                    {
                        foreach (RuleToken t in alList) // must be a member of the classes list
                        {
                            if (g.getCourse() == t.GetTokenName())
                                return true; // if it is, the rule has been met
                        }
                        return false; // if we found a class held in that room that was not on the list, the rule has been broken
                    }
                }
                return true; // if no classes in the schedule are held in this room, then the rule has not been broken, even if that is undesirable
            }
        } // CrosscheckRule
    } // RMCode

    /// <summary>
    /// Class for holding importand data about this rule type. Inherits from RuleCode.
    /// </summary
    class CLCode : RuleCode
    {
        public string sCourse; // the course that can be held in the rooms in the list

        /// <summary>
        /// Constructor. Assigns all important data to the data members of the class.
        /// </summary>
        /// <param name="sInCode"></param>
        /// <param name="sInCourse"></param>
        /// <param name="alInList"></param>
        public CLCode(RuleToken sInCode, string sInCourse, ArrayList alInList)
        {
            rtCode = sInCode;
            sCourse = sInCourse;
            alList = alInList;
        } // CLCode
        
        /// <summary>
        /// Overrides the abstract function in the parent abstract class RuleCode. Checks the
        ///     schedule to see if the rule is followed by all genes.
        /// </summary>
        /// <param name="sch"></param>
        /// <returns></returns>
        public override bool CrosscheckRule(Schedule sch)
        {
            foreach (Gene g in sch)           // every course in the schedule...
            {
                if (g.getCourse() == sCourse) // that is this course...
                {
                    foreach (RuleToken t in alList) // must be held in one of the rooms in the list
                    {
                        if (g.getRoom() == t.GetTokenName())
                            return true;      // if it is, then the rule has been met
                    }
                    return false;             // if not: No! Bad schedule! Listen to your rules! 
                }
            }
            return true; // if this class does not appear in the schedule, the rule has not been broken, even if this is undesirable
        } // CrosscheckRule
    } // CLCode

    /// <summary>
    /// Class for holding importand data about this rule type. Inherits from RuleCode.
    /// </summary
    class BDCode : RuleCode
    {
        public string sCourseAttr; // the attribute whose courses can only be held in the list of buildings

        /// <summary>
        /// Constructor. Assigns all important data to the data members of the class.
        /// </summary>
        /// <param name="rtInCode"></param>
        /// <param name="sInCourseAttr"></param>
        /// <param name="alInList"></param>
        public BDCode(RuleToken rtInCode, string sInCourseAttr, ArrayList alInList)
        {
            rtCode = rtInCode;
            sCourseAttr = sInCourseAttr;
            alList = alInList;
        } // BDCode

        /// <summary>
        /// Overrides the abstract function in the parent abstract class RuleCode. Checks the
        ///     schedule to see if the rule is followed by all genes.
        /// </summary>
        /// <param name="sch"></param>
        /// <returns></returns>
        public override bool CrosscheckRule(Schedule sch)
        {
            foreach (Gene g in sch)                  // each class...
            {
                if (g.getSubject() == sCourseAttr) // with this attribute...
                {
                    bool bExists = false;
                    foreach (RuleToken t in alList)  // must be held in one of the buildings on this list
                    {
                        if (g.getBuilding() == t.GetTokenName())
                            bExists = true;            // if it is, note that
                    }
                    if (!bExists)                      // if the attribute was not held in a good building, 
                        return false;                  // we have a bad schedule
                }
            }
    
            return true; // if all attributes were held in appropriate buildings, the rule has been met
        } // CrosscheckRule
    } //BDCode
}
